/**
 * @file BootLoader.c
 * @brief
 * @author F00
 * @date 2025-05-22
 */

#include "RTE.h"

typedef enum
{
    BootLoader_State_CheckCRC,       // 校验
    BootLoader_State_WaitJump,       // 等待跳转
    BootLoader_State_UpDate_Wait,    // 等待更新请求
    BootLoader_State_UpDate_Erase,   // 擦除Flash
    BootLoader_State_UpDate_Receive, // 接收数据
    BootLoader_State_UpDate_Write,   // 写入Flash
    BootLoader_State_UpDate_Check,   // 检查Flash
} BootLoader_State_t;                // BootLoader状态

typedef struct
{
    uint8_t Data[1024];
    uint16_t DataSize;
    uint32_t DataAddress;
} AppFlashData_t; // 接收数据(SD卡、CAN、UART等)

static AppFlashData_t AppFlashData;                                     // 接收数据
static BootLoader_State_t BootLoader_State = BootLoader_State_CheckCRC; // BootLoader状态

static void JumpToApp(void);
static bool SoftWare_CheckCRC(void);
static void SoftWare_WriteCRC(void);

/**
 * @brief 跳转到应用程序
 *
 */
static void JumpToApp(void)
{
    __disable_irq(); // 禁用中断
    // MCU_DeInit(); // 跳转到新的应用程序之前，关闭或重置一些硬件外设
    __set_PSP(*(uint32_t *)APP_FLASH_START_ADDR);                  // 设置进程堆栈指针（PSP）
    __set_MSP(*(uint32_t *)APP_FLASH_START_ADDR);                  // 设置主堆栈指针（MSP）
    __ASM("bx %0" ::"r"(*(uint32_t *)(APP_FLASH_START_ADDR + 4))); // 跳转到应用程序的复位向量地址
}

/**
 * @brief 检查软件是否正常
 *
 * @return true
 * @return false
 */
static bool SoftWare_CheckCRC(void)
{
    uint32_t CRC_Read = 0;
    uint32_t CRC_Calc = 0;

    MemoryCopy((uint8_t *)&CRC_Read, (uint8_t *)(APP_FLASH_CRC_ADDR), sizeof(CRC_Read));

    CRC_Calc = CRC_Calculate((uint32_t *)(APP_FLASH_START_ADDR), APP_FLASH_SIZE);

    if (CRC_Read != CRC_Calc)
    {
        return false;
    }

    return true;
}

/**
 * @brief 软件写入CRC
 *
 */
static void SoftWare_WriteCRC(void)
{
    uint32_t CRC_Calc = 0;

    CRC_Calc = CRC_Calculate((uint32_t *)(APP_FLASH_START_ADDR), APP_FLASH_SIZE / 4);

    PFlash_Write(APP_FLASH_CRC_ADDR, (uint8_t *)&CRC_Calc, sizeof(CRC_Calc));
}

/**
 * @brief 接收应用程序数据
 *
 * @return BootLoader_State_t 下一步BootLoader转跳状态
 */
static BootLoader_State_t Get_ReceiveData_State(void)
{
    static int64_t ReceiveData_Timer = 0;
    switch (RTE_Read_FunInd(RTE_FUNIND_Receive_State))
    {
    case RTE_Receive_State_Fail: // 接收失败
        ReceiveData_Timer = 0;   // 重置接收数据计时器
        return BootLoader_State_CheckCRC;

    case RTE_Receive_State_Complete:     // 接收完成
        ReceiveData_Read(&AppFlashData); // 读取接收数据
        ReceiveData_Timer = 0;           // 重置接收数据计时器
        return BootLoader_State_UpDate_Write;

    case RTE_Receive_State_End: // APP数据接收结束
        ReceiveData_Timer = 0;  // 重置接收数据计时器
        return BootLoader_State_UpDate_Check;

    default: // 接收中
        if (ReceiveData_Timer == 0)
        {
            ReceiveData_Timer = GetSysTick_ms(); // 记录接收数据计时器
        }
        else if (GetSysTick_ms() - ReceiveData_Timer >= Time_1s * 5)
        {
            ReceiveData_Timer = 0;            // 重置接收数据计时器
            return BootLoader_State_CheckCRC; // 超时，接收失败
        }
        return BootLoader_State_UpDate_Receive;
    }
}

/**
 * @brief BootLoader主函数
 *
 */
void BootLoader_Task(void)
{
    static int64_t BootLoader_Timer = 0;
    switch (BootLoader_State)
    {
    case BootLoader_State_CheckCRC:                      // App校验
        BootLoader_State = BootLoader_State_UpDate_Wait; // 校验失败，等待软件更新请求
        if (SoftWare_CheckCRC())
        {
            BootLoader_Timer = GetSysTick_ms();           // 校验成功，记录时间戳
            BootLoader_State = BootLoader_State_WaitJump; // 校验成功，等待跳转到应用程序
        }
        break;

    case BootLoader_State_WaitJump: // 等待跳转
        if (GetSysTick_ms() - BootLoader_Timer >= Time_1ms * 100)
        {
            JumpToApp(); // 时间超过100ms，跳转到应用程序
        }
        else if (RTE_Read_FunInd(RTE_FUNIND_UpDateRequest) == 1)
        {
            BootLoader_State = BootLoader_State_UpDate_Erase; // 有更新请求，进入擦除状态
            BootLoader_Timer = 0;                             // 重置时间戳
            RTE_Write_FunInd(RTE_FUNIND_UpDateRequest, 0);    // 软件更新请求
        }
        break;

    case BootLoader_State_UpDate_Wait: // 校验失败 等待SD卡插入、CAN、UART等更新请求
        if (RTE_Read_FunInd(RTE_FUNIND_UpDateRequest) == 1)
        {
            BootLoader_State = BootLoader_State_UpDate_Erase; // 擦除请求，进入擦除状态
            RTE_Write_FunInd(RTE_FUNIND_UpDateRequest, 0);    // 软件更新请求
        }
        break;

    case BootLoader_State_UpDate_Erase:               // 擦除Flash
        BootLoader_State = BootLoader_State_CheckCRC; // 擦除失败，重新启动流程
        if (PFlash_Erase() == true)
        {
            BootLoader_State = BootLoader_State_UpDate_Write; // 擦除成功，进入写入状态
        }
        break;

    case BootLoader_State_UpDate_Receive:           // 接收数据
        BootLoader_State = Get_ReceiveData_State(); // 接收应用程序数据
        break;

    case BootLoader_State_UpDate_Write:               // 写入Flash
        BootLoader_State = BootLoader_State_CheckCRC; // 写入失败，重新启动流程
        if (PFlash_Write(AppFlashData.DataAddress, AppFlashData.Data, AppFlashData.DataSize) == true)
        {
            BootLoader_State = BootLoader_State_UpDate_Receive; // 写入成功，继续接收数据
        }
        break;

    case BootLoader_State_UpDate_Check:               // 写入完成，校验数据
        BootLoader_State = BootLoader_State_CheckCRC; // 重新启动流程
        SoftWare_WriteCRC();                          // 写入CRC
        break;

    default:
        BootLoader_State = BootLoader_State_CheckCRC; // 默认状态，重新校验
        break;
    }
}